//
//  ViewController.swift
//  ArRich
//
//  Created by Apple on 2018/1/4.
//  Copyright © 2018年 Apple. All rights reserved.
//

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController {
    
    @IBOutlet var sceneView: ARSCNView!
    
    @IBOutlet weak var sessionInfoLabel: UILabel!
    
    @IBOutlet weak var playButton: UIButton!
    
    @IBOutlet weak var restartButton: UIButton!
    
    @IBOutlet weak var playerInfoLabel: UILabel!
    
    @IBOutlet weak var player2InfoLabel: UILabel!
    
    @IBOutlet weak var diceButton: UIButton!
    
    @IBOutlet weak var endTurnButton: UIButton!
    
    @IBOutlet weak var errorLabel: UILabel!
    
    @IBOutlet weak var diceResultLabel: UILabel!
    
    @IBOutlet weak var buildButton: UIButton!
    
    
    var chess1: SCNNode?
    var chess2: SCNNode?
    var dice: SCNNode?
    var placeInfo = PlaceInfo()
    
    
    var buildingPosition:SCNVector3?
    var buyCost:Int? = 0
    
    
    var round: Int = 0
    
    var player1 = Player()
    var player2 = Player()
    
    
    // 识别出平面后,放上游戏的基础节点,相对固定于真实世界场景中
    weak var baseNode: SCNNode?
    // 识别出平面锚点后,用来标识识别的平面,会不断刷新大小和位置
    weak var planeNode: SCNNode?
    // 刷新次数,超过一定次数才说明这个平面足够明显,足够稳定.可以开始游戏
    var updateCount: NSInteger = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        playButton.isHidden = true
        diceButton.isHidden = true
        playerInfoLabel.isHidden = true
        player2InfoLabel.isHidden = true
        errorLabel.isHidden = true
        diceResultLabel.isHidden = true
        endTurnButton.isHidden = true
        buildButton.isHidden = true
        // Set the view's delegate
        sceneView.delegate = self
        
        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true
        //显示debug特征点
        sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
        // Create a new scene
        let scene = SCNScene()
        // Set the scene to the view
        sceneView.scene = scene
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard ARWorldTrackingConfiguration.isSupported else {
            fatalError("""
                ARKit is not available on this device. For apps that require ARKit
                for core functionality, use the `arkit` key in the key in the
                `UIRequiredDeviceCapabilities` section of the Info.plist to prevent
                the app from installing. (If the app can't be installed, this error
                can't be triggered in a production scenario.)
                In apps where AR is an additive feature, use `isSupported` to
                determine whether to show UI for launching AR experiences.
            """) // For details, see https://developer.apple.com/documentation/arkit
        }
        //重置界面,参数,追踪配置
        resetAll()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Pause the view's session
        sceneView.session.pause()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }
    
    @IBAction func playButtonClick(_ sender: UIButton) {
        //0.隐藏按钮,显示玩家信息
        playButton.isHidden = true
        
        sessionInfoLabel.isHidden = true
        
        playerInfoLabel.isHidden = false
        player2InfoLabel.isHidden = false
        playerInfoLabel.text = "玩家1: " + String(player1.money)
        player2InfoLabel.text = "玩家2: " + String(player2.money)
        
        diceButton.isHidden = false
        round += 1
        
        //1.停止平面检测
        stopTracking()
        //2.不显示辅助点
        sceneView.debugOptions = []
        //3.更改平面的透明度和颜色
        planeNode?.geometry?.firstMaterial?.diffuse.contents = UIColor.clear
        planeNode?.opacity = 1
        //4.载入游戏场景
        
        //载入棋子
        let chess1Node = SCNNode(geometry: SCNSphere(radius: 0.01))
        chess1Node.geometry?.firstMaterial?.diffuse.contents = UIColor.red
        chess1Node.position = SCNVector3Make(0.19 , 0.03 , 0.19 )
        baseNode?.addChildNode(chess1Node)
        self.chess1 = chess1Node
        
        let chess2Node = SCNNode(geometry: SCNSphere(radius: 0.01))
        chess2Node.geometry?.firstMaterial?.diffuse.contents = UIColor.green
        chess2Node.position = SCNVector3Make(0.22 , 0.03 , 0.22 )
        
        baseNode?.addChildNode(chess2Node)
        self.chess2 = chess2Node
        
        //创建骰子
        
        let scene = SCNScene (named: "art.scnassets/dice.scn")
        let diceNode = scene?.rootNode
        diceNode?.scale = SCNVector3(0.03 , 0.03 , 0.03)
        baseNode?.addChildNode(diceNode!)
        self.dice = diceNode
        
        
        
    }
    
    @IBAction func diceButtonClick(_ sender: UIButton) {
        
        let result = Int(arc4random_uniform(6)+1)
        let cityName: String?
        let owner: String?
//        let chessPosition : SCNVector3
        
        if round == 1{
            
            
            player1.position += result
            
            let currentPosition = player1.position % 40
            
            let placeName = "place" + String(currentPosition)
            
//            chessPosition = placeInfo.placeList[placeName]!["chessPosition"] as! SCNVector3
            let x = placeInfo.placeList[placeName]!["chessPositionX"] as! Float
            let z = placeInfo.placeList[placeName]!["chessPositionZ"] as! Float

            chess1?.position = SCNVector3(x,0.0,z)
            
            cityName = placeInfo.placeList[placeName]?["name"] as? String
            owner = placeInfo.placeList[placeName]?["owner"] as? String
            
            diceResultLabel.isHidden = false
            if owner == "player2" {
                player1.money -= 2000
                player2.money += 2000
                buildButton.isHidden = true
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家1掷出了" + String(result) + "点，支付2000"

            }
            
            if owner == "player1" {
                buildButton.isHidden = true
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家1掷出了" + String(result) + "点，到达" + cityName!

            }
            
            if owner == "" {
                buildButton.isHidden = false
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家1掷出了" + String(result) + "点，到达" + cityName!

            }
            //骰子结果
            
            
        }else if round == 2{
            
            player2.position += result
            chess1?.position = SCNVector3Make(Float(0.19 - (Double(result) * 0.05)), 0.03, 0.19)
            let currentPosition = player2.position % 40
            
            let placeName = "place" + String(currentPosition)
            
            cityName = placeInfo.placeList[placeName]?["name"] as? String
            owner = placeInfo.placeList[placeName]?["owner"] as? String
            let payCost = placeInfo.placeList[placeName]!["buyCost"]
            diceResultLabel.isHidden = false
            if owner == "player1" {
                player1.money -= payCost as! Int
                player2.money += payCost as! Int
                buildButton.isHidden = true
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家2掷出了" + String(result) + "点，支付" + String(describing: payCost)
                
            }
            
            if owner == "player2" {
                buildButton.isHidden = true
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家2掷出了" + String(result) + "点，到达" + cityName!
                
            }
            
            if owner == "" {
                buildButton.isHidden = false
                endTurnButton.isHidden = false
                diceResultLabel.text = "玩家2掷出了" + String(result) + "点，到达" + cityName!
                
            }
            
        }
        //骰子转动动画（施工中）
        let rotation = CABasicAnimation(keyPath: "rotation")
        rotation.fromValue = SCNVector4(x: 0, y: 0, z: 0, w: 0)
        rotation.toValue = SCNVector4(x: 0, y: 1, z: 0, w: 6.28)
        rotation.duration = 0.2
        rotation.repeatCount = 10
        dice?.addAnimation(rotation, forKey: "rotation")
        
        let moveDiceUp = SCNAction.moveBy(x: 0.0, y: 1.0, z: 0.0, duration: 1.0)
        let moveDiceDown = SCNAction.moveBy(x: 0.0, y: -1.0, z: 0.0, duration: 1.0)
        let seq = SCNAction.sequence([moveDiceUp,moveDiceDown])
        let repeatSeq = SCNAction.repeat(seq, count: 1)
        dice?.runAction(repeatSeq)
        dice?.eulerAngles = SCNVector3(0,0,90)
        dice?.position = SCNVector3(0,0.03,0)
        
        
//        switch result {
//        case 1:
//            newDice =
//        case 2:
//            dice?.eulerAngles = SCNVector3(0,0,135)
            //dice?.position = SCNVector3(0, 0.03, 0)
//        case 3:
//            dice?.eulerAngles = SCNVector3(0,0,-90)
//        case 4:
//            dice?.eulerAngles = SCNVector3(0,0,0)
//        case 5:
//            dice?.eulerAngles = SCNVector3(0,0,90)
//        case 6:
//            dice?.eulerAngles = SCNVector3(-90,0,0)
//        default:
//            dice?.eulerAngles = SCNVector3(90,0,0)
//
//        }
        
        
        diceButton.isHidden = true
        endTurnButton.isHidden = false
        buildButton.isHidden = false

    }
    
    
    @IBAction func buildButtonClick(_ sender: UIButton) {
        let position = player1.position
        let currentPosition = position % 40
        let placeName = "place" + String(currentPosition)
        let buildingPosition = placeInfo.placeList[placeName]!["buildPosition"] as! SCNVector3
        let buyCost:Int = placeInfo.placeList[placeName]!["buyCost"] as! Int
        
        
        if round == 1{
            
            let money = player1.money
            if money >= buyCost {
                let scene = SCNScene (named: "art.scnassets/building1.scn")
                let buildingNode = scene?.rootNode
                buildingNode?.position = buildingPosition
                buildingNode?.scale = SCNVector3(0.03 , 0.03 , 0.03)
                baseNode?.addChildNode(buildingNode!)
                
                let moveBuilding = SCNAction.moveBy(x:0.0, y:0.03, z:0.0 , duration: 1.0)
                
                let seq = SCNAction.sequence([moveBuilding])
                let repeatSeq = SCNAction.repeat(seq, count: 1)
                buildingNode?.runAction(repeatSeq)
            
                player1.money = money - buyCost
                playerInfoLabel.text = "玩家1: " + String(player1.money)
                placeInfo.placeList[placeName]!["owner"] = "player1"
                
            }
            else if money < buyCost {
                errorLabel.isHidden = false
                diceResultLabel.isHidden = true
                errorLabel.text = "您的金钱不足，无法购买/建造"
            }
            
        }
        if round == 2{
            let money = player2.money
            if money >= buyCost {
                let scene = SCNScene (named: "art.scnassets/building2.scn")
                let buildingNode = scene?.rootNode
                buildingNode?.position = buildingPosition
                buildingNode?.scale = SCNVector3(0.03 , 0.03 , 0.03)
                baseNode?.addChildNode(buildingNode!)
                
                let moveBuilding = SCNAction.moveBy(x:0.0, y:0.03, z:0.0 , duration: 1.0)
                
                let seq = SCNAction.sequence([moveBuilding])
                let repeatSeq = SCNAction.repeat(seq, count: 1)
                buildingNode?.runAction(repeatSeq)
                
                player1.money = money - buyCost
                playerInfoLabel.text = "玩家2: " + String(player1.money)
                placeInfo.placeList[placeName]!["owner"] = "player2"
                
            }
            else if money < buyCost {
                errorLabel.isHidden = false
                diceResultLabel.isHidden = true
                errorLabel.text = "您的金钱不足，无法购买/建造"
            }
            
        }
            
        
    }
    
    
    @IBAction func endTurnButtonClick(_ sender: Any) {
        if round == 1{
            self.round += 1
            diceButton.isHidden = false
            endTurnButton.isHidden = true
            errorLabel.isHidden = true
            
        }
        else if round == 2{
            self.round -= 1
            diceButton.isHidden = false
            endTurnButton.isHidden = true
            errorLabel.isHidden = true
        }
    }
    
    @IBAction func restartButtonClick(_ sender: UIButton) {
        resetAll()
    
    }
    
}



// MARK:- 私有方法
extension ViewController {
    
    private func updateSessionInfoLabel(for frame: ARFrame, trackingState: ARCamera.TrackingState) {
        // 更新UI,反馈AR状态.
        let message: String
        print("status")
        switch trackingState {
        case .normal where frame.anchors.isEmpty:
            // 未检测到平面
            message = "移动设备来探测水平面."
            
        case .normal:
            // 平面可见,跟踪正常,无需反馈
            message = ""
            
        case .notAvailable:
            message = "无法追踪."
            
        case .limited(.excessiveMotion):
            message = "追踪受限-请缓慢移动设备."
            
        case .limited(.insufficientFeatures):
            message = "追踪受限-将设备对准平面上的可见花纹区域,或改善光照条件."
            
        case .limited(.initializing):
            message = "初始化AR中."
            
        }
        print(message)
        sessionInfoLabel.text = message
        sessionInfoLabel.isHidden = message.isEmpty
    }
    
    private func resetTracking() {
        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = .horizontal
        configuration.isLightEstimationEnabled = true
        sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }
    private func stopTracking() {
        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = .init(rawValue: 0)
        configuration.isLightEstimationEnabled = true
        sceneView.session.run(configuration)
    }
    
    private func resetAll() {
        //0.显示按钮
        playButton.isHidden = true
        sessionInfoLabel.isHidden = false
        diceButton.isHidden = true
        playerInfoLabel.isHidden = true
        
        //1.重置平面检测配置,重启检测
        resetTracking()
        //2.重置更新次数
        updateCount = 0
        sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
    }
}

extension ViewController:ARSCNViewDelegate {
    // MARK: - ARSCNViewDelegate
    
    // 识别到新的锚点后,添加什么样的node.不实现该代理的话,会添加一个默认的空的node
    // ARKit会自动管理这个node的可见性及transform等属性等,所以一般把自己要显示的内容添加在这个node下面作为子节点
    //    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    //
    //        let node = SCNNode()
    //
    //        return node
    //    }
    
    // node添加到新的锚点上之后(一般在这个方法中添加几何体节点,作为node的子节点)
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        //1.获取捕捉到的平地锚点,只识别并添加一个平面
        if let planeAnchor = anchor as? ARPlaneAnchor,node.childNodes.count < 1,updateCount < 1 {
            print("捕捉到平地")
            //2.创建一个平面    （系统捕捉到的平地是一个不规则大小的长方形，将其变成一个长方形）
            let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
            //3.使用Material渲染3D模型（默认模型是白色的，改成红色）
            plane.firstMaterial?.diffuse.contents = UIColor.red
            //4.创建一个基于3D物体模型的节点
            planeNode = SCNNode(geometry: plane)
            //5.设置节点的位置为捕捉到的平地的锚点的中心位置  SceneKit框架中节点的位置position是一个基于3D坐标系的矢量坐标SCNVector3Make
            planeNode?.simdPosition = float3(planeAnchor.center.x, 0, planeAnchor.center.z)
            //6.`SCNPlane`默认是竖着的,所以旋转一下以匹配水平的`ARPlaneAnchor`
            planeNode?.eulerAngles.x = -.pi / 2
            
            //7.更改透明度
            planeNode?.opacity = 0.25
            //8.添加到父节点中
            node.addChildNode(planeNode!)
            
            //9.上面的planeNode节点,大小/位置会随着检测到的平面而不断变化,方便起见,再添加一个相对固定的基准平面,用来放置游戏场景
            let base = SCNBox(width: 0.5, height: 0.01, length: 0.5, chamferRadius: 0);
            base.firstMaterial?.diffuse.contents = UIImage(named:"Image");
            baseNode = SCNNode(geometry:base);
            baseNode?.position = SCNVector3Make(planeAnchor.center.x, 0, planeAnchor.center.z);
            
            node.addChildNode(baseNode!)
        }
    }
    
    // 更新锚点和对应的node之前调用,ARKit会自动更新anchor和node,使其相匹配
    func renderer(_ renderer: SCNSceneRenderer, willUpdate node: SCNNode, for anchor: ARAnchor) {
        // 只更新在`renderer(_:didAdd:for:)`中得到的配对的锚点和节点.
        guard let planeAnchor = anchor as?  ARPlaneAnchor,
            let planeNode = node.childNodes.first,
            let plane = planeNode.geometry as? SCNPlane
            else { return }
        
        updateCount += 1
        if updateCount > 20 {//平面超过更新20次,捕捉到的特征点已经足够多了,可以显示进入游戏按钮
            DispatchQueue.main.async {
                self.playButton.isHidden = false
            }
        }
        
        // 平面的中心点可以会变动.
        planeNode.simdPosition = float3(planeAnchor.center.x, 0, planeAnchor.center.z)
        
        /*
         平面尺寸可能会变大,或者把几个小平面合并为一个大平面.合并时,`ARSCNView`自动删除同一个平面上的相应节点,然后调用该方法来更新保留的另一个平面的尺寸.(经过测试,合并时,保留第一个检测到的平面和对应节点)
         */
        plane.width = CGFloat(planeAnchor.extent.x)
        plane.height = CGFloat(planeAnchor.extent.z)
    }
    
    // 更新锚点和对应的node之后调用
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        
    }
    // 移除锚点和对应node后
    func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
        
    }
    
    // MARK: - ARSessionObserver
    
    func session(_ session: ARSession, didFailWithError error: Error) {
        
        sessionInfoLabel.text = "Session失败: \(error.localizedDescription)"
        resetTracking()
    }
    
    func sessionWasInterrupted(_ session: ARSession) {
        
        sessionInfoLabel.text = "Session被打断"
    }
    
    func sessionInterruptionEnded(_ session: ARSession) {
        
        sessionInfoLabel.text = "Session打断结束"
        resetTracking()
    }
    
    func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
        updateSessionInfoLabel(for: session.currentFrame!, trackingState: camera.trackingState)
    }
}

